package model;
import java.util.*;

import excepciones.NoSeReferencioPacmanException;
import view.vistaObjeto;
import ar.uba.fi.algo3.titiritero.Dibujable;
import generadores.Generador;
import model.common.Constantes;
import model.common.Numero;
import model.fantasmas.Fantasma;
import model.movimiento.*;
import model.objetos.Objetos;
import model.posicion.Posicion;

public class Laberinto {

	private static Numero vidas=new Numero(Constantes.VIDAS);
	private Objetos[][] tablero;
	private Numero puntaje;
	private Generador generador;
	private List<Fantasma> fantasmas;
	private Pacman pacman;
	private int puntosRestantes;//son las casillas que qeudan por comer para terminar el jueg.
	
	
	/**
	 * Crea una instancia de Laberinto
	 */
	public Laberinto(int nivel) {
					
			this.puntaje=new Numero(0);
			this.generador = new Generador(this,nivel);
			this.tablero=this.generador.getGrilla();
			this.fantasmas = this.generador.getFantasmas();
			this.puntosRestantes=this.generador.getPuntosLaberinto();
	}
	
	public void avanzarNivel() {
		
		this.puntaje=new Numero(0);
		this.generador.avanzarNivel();
		this.puntosRestantes=this.generador.getPuntosLaberinto();
}

	public void sumarPuntos(int puntos) {	
		
		this.puntaje.sumar(puntos);		
	}

	public Posicion pisarCelda(Posicion objeto, Posicion pacman){                 
		if (tablero[objeto.getPosX()][objeto.getPosY()].accesible())                         
			return tablero[objeto.getPosX()][objeto.getPosY()].getPosicion();//nueva posicion, se la pregunto asi poruq de esta manera puedo crear los objetos transportadores                 
		return pacman;         
	} 

	public Posicion avanzar(Posicion posicion,Movimientos direccion){                 
		return direccion.devuelvoPosicion(this, posicion);         
	}
	
	public Numero getPuntajeReferencia(){                 
		return puntaje;         
	}
	
	public int getPuntaje(){                 
		return puntaje.getValor();         
	}
	
	public Numero getVidasReferencia(){                 
		return vidas;         
	}
	
	public int getVidas(){                 
		return vidas.getValor();         
	}
	
	public int getLimiteX() {                 
		return this.generador.getLimiteX();        
	}
	
	public int getLimiteY() {                 
		return this.generador.getLimiteY();         
	}
	
	public Objetos[][] getTablero() {                 
		return tablero;         
	}
		
	public List<Movimientos> movimientosPosibles(Posicion posicion) {                                  
		
		List<Movimientos> posiblesMovimientos = new ArrayList<Movimientos>(4);//son las maximas posibles direcciones que se pueden tomar                                  
		
		//nos vamos a fijar si la casilla de arriba esta dentro del tablero y que sea accesible para meter una posible direccion que sea arriba                 
		if(posicion.getPosY()-1>=0){                                                     
					if(this.tablero[posicion.getPosX()][posicion.getPosY()-1].accesible()){                                                          
							posiblesMovimientos.add(new MovimientoArriba());                                 
					}                 
		}                                  
		
		//nos vamos a fijar si la casilla de abajo esta dentro del tablero y que sea accesible para meter una posible direccion que sea abajo                 
		if(posicion.getPosY()+1<this.generador.getLimiteY()){                         
				if(this.tablero[posicion.getPosX()][posicion.getPosY()+1].accesible()){                                                  
						posiblesMovimientos.add(new MovimientoAbajo());                         
				}                 
		}                                  
		
		if(posicion.getPosX()+1<this.generador.getLimiteX()){                                 
						if(this.tablero[posicion.getPosX()+1][posicion.getPosY()].accesible()){                                                          
								posiblesMovimientos.add(new MovimientoDerecha());                                 
						}                 
		}                                  
		
		if(posicion.getPosX()-1>=0){                         
				if(this.tablero[posicion.getPosX()-1][posicion.getPosY()].accesible()){                                                  
						posiblesMovimientos.add(new MovimientoIzquierda());                         
				}                 
		}                                                   
		
		
		return posiblesMovimientos;         
	} 

	public void setFantasmasComibles() {                  
		Fantasma fantasma;
		Iterator<Fantasma> iterador = this.fantasmas.iterator();
		while(iterador.hasNext()){
			fantasma = iterador.next();
			fantasma.cambiarEstadoComible();
		}
	}
	
	public List<Fantasma> getFantasmas(){
		return this.fantasmas;
	}
	
	public Posicion getInicioPacman(){
		return this.generador.getpPacman();
	}

	public int getAncho() {
		//ancho en pixels
		return this.getLimiteX()*Constantes.ANCHO;
	}

	public int getAlto() {
		
		return this.getLimiteY()*Constantes.ALTO;
	}

	public List<Dibujable> getDibujables() {
		
		List<Dibujable> dibujables = new ArrayList<Dibujable>();
		
		for(Objetos[] vectorObjetos : this.tablero){
			for(Objetos objeto : vectorObjetos){
				vistaObjeto cuadrado = new vistaObjeto(objeto);
				cuadrado.setPosicionable(objeto);
				dibujables.add(cuadrado);
			}
		}
		return dibujables;
	}

	public List<Dibujable> getFantasmasDibujables() {
		return this.generador.getFantasmasDibujar();
	}
	
	public void setPacman(Pacman pacman) {// este metodo sirve para tener un registro de la posicion del pacman, porque el metodo vivir no toma parametros, asi que en vez de reimplementar la interface cree esto para que los fantasmas puedan preguntar la posicion del pacman, es importante setear el pacman antes de poner vivos los fantasmas
		this.pacman = pacman;
	}
	
	public Posicion getPosPacman(){
		if (this.pacman==null) 
			throw new NoSeReferencioPacmanException(); 
		else
			return this.pacman.getPosicion();
	}
	
	public boolean interseccion(List<Movimientos> movimientos,Movimientos direccion) {
		//devuelve si el fantasma se encuentra en una inteseccion, que es un lugar donde halla 3 o 4 posibles direccion que tomar o que este en una esquina poruq el fanstama solo cambia la direccion en una de estas.
		if(movimientos.size()>2) 
			return true;
		if( (movimientos.size()==2) && ((movimientos.get(0).movimientoString().equals(direccion.movimientoString())) || (movimientos.get(1).movimientoString().equals(direccion.movimientoString())))) 
			return false; 
		else 
			return true;
	}

	public int getPuntosRestantes() {
		return this.puntosRestantes;
	}

	public void restarPuntosLaberinto() {
		this.puntosRestantes-=1;
	}

	public void restarVida() {
		Laberinto.vidas.sumar(-1);
	}
} 
